﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AAA.Chart.Data;
using AAA.Chart.Indicator;
using System.Drawing.Drawing2D;
using AAA.Meta.Quote;
using AAA.Meta.Chart;

namespace AAA.Chart.Component
{
    public partial class ChartX : ChartBase
    {        
        public ChartX()
        {
            InitializeComponent();
        }

        private void DrawChartArea(Graphics g)
        {
            try
            {
                Pen pen = new Pen(new SolidBrush(AxisLineColor));
                Pen penHour = new Pen(new HatchBrush(HatchStyle.DashedHorizontal, HourLineColor));
                Pen customPen;
                int iHeight = DrawHeight;
                double dCount = Math.Floor(iHeight / (double)ChartConstants.DEFAULT_INTERVAL);
                //double dInterval = (YMax - YMin) / dCount;                                                
                double dInterval;
                double dCurrent;
                int iPosition;
                int iCount;
                int iXSkipCount;
                string strDateTimeFormat;
                string strDateSeparateFormat;
                string strDrawString;
                int iDataLength;
                int iYAxisStart;
                int iYNumberStart;

                SizeF sDateSize;
                DateTime dtCurrent;
                DateTime dtPrevious;
                BarCompressionEnum eCompression;

                g.Clear(BackColor);
                eCompression = GetIndicators().Count == 0
                                ? BarCompressionEnum.Min_1
                                : DataSource.GetData(GetIndicators()[0].BaseStudy) == null
                                    ? BarCompressionEnum.Min_1
                                    : DataSource.GetData(GetIndicators()[0].BaseStudy).BarCompression;

                dInterval = CalculateInterval(YMax, YMin, dCount);
                iCount = (int)Math.Max(0, Math.Floor((((dInterval * dCount) + YMin) - YMax) / dInterval / 2) - 1);
                //dCurrent = (Math.Floor(YMin / dInterval) - iCount) * dInterval;
                dCurrent = YMin - iCount * dInterval;
                while (dCurrent > YMin)
                    dCurrent -= dInterval;
                _dMinValue = dCurrent;

                //Y軸一個Pixel代表的數值
                _dPixelValue = dInterval / (double)ChartConstants.DEFAULT_INTERVAL;
                dCurrent += dInterval;

                //X2軸一個Pixel代表的數值
                _dX2PixelValue = (X2Max - X2Min) / DrawWidth;
                _dX2MinValue = X2Min;

                //刻度的起始X座標
                iYAxisStart = (YAxisPosition == ChartConstants.RIGHT) ? Width - RightPad - (ShowYAxis ? _iAxisWidth : 0) : LeftPad + (ShowYAxis ? _iAxisWidth - 3 : 0);
                //標示數字的起始X座標
                iYNumberStart = (YAxisPosition == ChartConstants.RIGHT) ? iYAxisStart + 5 : 2;

                //若顯示X軸, 畫出X軸
                if (ShowXAxis)
                {
                    switch (eCompression)
                    {
                        case BarCompressionEnum.Tick:
                            strDateTimeFormat = "mm:ss";
                            strDateSeparateFormat = "HH:mm";
                            break;
                        case BarCompressionEnum.Daily:
                            strDateTimeFormat = "MM/dd";
                            strDateSeparateFormat = "yy/MM";
                            break;
                        default:
                            strDateTimeFormat = "HH:mm";
                            strDateSeparateFormat = "MM/dd";
                            break;
                    }

                    g.DrawLine(pen, 0, _fYOrigin, Width, _fYOrigin);

                    //計算時間字串的寬度
                    sDateSize = GetIndicators().Count == 0
                                    ? new SizeF(10, 10)
                                    : DataSource.GetData(GetIndicators()[0].BaseStudy) == null
                                        ? new SizeF(10, 10)
                                        : g.MeasureString(DataSource.GetData(GetIndicators()[0].BaseStudy).DateTime().ToString(strDateTimeFormat), Font);

                    //計算每個時間寬度所要跳過的K棒數
                    iXSkipCount = (int)Math.Ceiling(sDateSize.Width / XInterval);

                    //計算X軸的刻度個數
                    dCount = DrawWidth / (XInterval * iXSkipCount);
                    iDataLength = EndIndex - StartIndex + 1;

                    //畫出X軸刻度
                    switch (XDataType)
                    {
                        case ChartConstants.DATA_TYPE_TIME:
                            for (int i = 0; i < dCount; i++)
                            {
                                dtCurrent = GetIndicators().Count == 0
                                                ? DateTime.Now
                                                : DataSource.GetData(GetIndicators()[0].BaseStudy) == null
                                                    ? DateTime.Now
                                                    : DataSource.GetData(GetIndicators()[0].BaseStudy).DateTime(i * iXSkipCount + StartIndex);

                                dtPrevious = GetIndicators().Count == 0
                                                    ? DateTime.Now
                                                    : DataSource.GetData(GetIndicators()[0].BaseStudy) == null
                                                        ? DateTime.Now
                                                        : (i - 1) * iXSkipCount + StartIndex < 0
                                                            ? DateTime.Now
                                                            : DataSource.GetData(GetIndicators()[0].BaseStudy).DateTime((i - 1) * iXSkipCount + StartIndex);
                                g.DrawLine(pen,
                                           new Point((int)_fXOrigin + iXSkipCount * i * XInterval, iHeight),
                                           new Point((int)_fXOrigin + iXSkipCount * i * XInterval, iHeight + 5));

                                if (dtCurrent == DateTime.MinValue)
                                    continue;
                                strDrawString = (dtCurrent.Day != dtPrevious.Day)
                                                    ? dtCurrent.ToString(strDateSeparateFormat)
                                                    : dtCurrent.ToString(strDateTimeFormat);

                                g.DrawString(strDrawString, Font, new SolidBrush(AxisLineColor),
                                             new Point((int)_fXOrigin + iXSkipCount * i * XInterval, iHeight + 5));
                            }
                            break;
                        case ChartConstants.DATA_TYPE_VALUE:
                            for (int i = 0; i < dCount; i++)
                            {
                                g.DrawLine(pen,
                                           new Point((int)_fXOrigin + iXSkipCount * i * XInterval, iHeight),
                                           new Point((int)_fXOrigin + iXSkipCount * i * XInterval, iHeight + 5));
                                strDrawString = PixelToValue((int)(_fXOrigin + iXSkipCount * i * XInterval), iHeight + 5)[0].ToString("0");
                                g.DrawString(strDrawString, Font, new SolidBrush(AxisLineColor),
                                             new Point((int)_fXOrigin + iXSkipCount * i * XInterval, iHeight + 5));

                            }
                            break;
                    }
                }

                //畫出Y軸
                g.DrawLine(pen, _fXOrigin, 0, _fXOrigin, _fYOrigin);

                if (ShowYAxis)
                {
                    for (iPosition = ChartConstants.DEFAULT_INTERVAL; iPosition < iHeight; dCurrent += dInterval, iPosition += ChartConstants.DEFAULT_INTERVAL)
                    {
                        g.DrawLine(pen, new Point(iYAxisStart, iHeight - iPosition), new Point(iYAxisStart + 3, iHeight - iPosition));
                        g.DrawString(dCurrent.ToString("0.00"), Font, new SolidBrush(AxisLineColor), new Point(iYNumberStart, iHeight - iPosition - (int)(Font.Height / 2)));
                    }
                }

                //顯示小時線
                if (IsShowHourLine && XDataType == ChartConstants.DATA_TYPE_TIME)
                {

                    for (int i = StartIndex; i < EndIndex; i++)
                    {
                        dtCurrent = GetIndicators().Count == 0
                                        ? DateTime.MinValue
                                        : DataSource.GetData(GetIndicators()[0].BaseStudy) == null
                                            ? DateTime.MinValue
                                            : DataSource.GetData(GetIndicators()[0].BaseStudy).DateTime(i);

                        if (dtCurrent.Minute == 0)
                            g.DrawLine(penHour,
                                       new Point((int)_fXOrigin + XInterval * (i - StartIndex), TopPad),
                                       new Point((int)_fXOrigin + XInterval * (i - StartIndex), (int)_fYOrigin));
                    }
                }




                /*
                                iDataLength = _lstIndicator.Count == 0
                                                    ? 0
                                                    : _dsDataSource.GetLength(_lstIndicator[0].BaseStudy);

                                eCompression = _lstIndicator.Count == 0
                                                ? BarCompressionEnum.Min_1 
                                                : _dsDataSource.GetData(_lstIndicator[0].BaseStudy) == null
                                                    ? BarCompressionEnum.Min_1 
                                                    : _dsDataSource.GetData(_lstIndicator[0].BaseStudy).BarCompression;
                
                                g.FillRectangle(new SolidBrush(BackColor), new Rectangle(0, 0, Width, Height));

                                g.DrawString(_lstIndicator.Count == 0
                                                ? ""
                                                : _lstIndicator[0].BaseStudy,
                                             Font, new SolidBrush(AxisLineColor),
                                             new Point(LeftPad + 2, TopPad + 2));
                                // Calculate Interval
                                dInterval = CalculateInterval(YMax, YMin, dCount);
                                iCount = (int)Math.Floor((((dInterval * dCount) + YMin) - YMax) / dInterval / 2) - 1;
                                dCurrent = (Math.Floor(YMin / dInterval) - iCount) * dInterval;
                                dCurrent = (dCurrent > YMin) ? dCurrent - dInterval : dCurrent;
                                _dMinValue = dCurrent;
                                _dPixelValue = dInterval / (double)DEFAULT_INTERVAL;

                                // Draw Axis Line
                                if (ShowXAxis)
                                    g.DrawLine(pen, new Point(0, Height - _iBottomPad), new Point(Width, Height - _iBottomPad));
                                g.DrawLine(pen, new Point(Width - _iRightPad, 0), new Point(Width - _iRightPad, iHeight));
                                dCurrent += dInterval;
                                for (iPosition = DEFAULT_INTERVAL; iPosition < iHeight; dCurrent += dInterval, iPosition += DEFAULT_INTERVAL)
                                {
                                    g.DrawLine(pen, new Point(Width - _iRightPad, iHeight - iPosition), new Point(Width - _iRightPad + 3, iHeight - iPosition));                    
                                    g.DrawString(dCurrent.ToString("0.00"), Font, new SolidBrush(AxisLineColor), new Point(Width - _iRightPad + 5, iHeight - iPosition - (int)(Font.Height / 2)));
                                }

                                switch (eCompression)
                                {
                                    case BarCompressionEnum.Tick:
                                        strDateTimeFormat = "MM/dd HH:mm:dd";
                                        break;
                                    case BarCompressionEnum.Daily:
                                        strDateTimeFormat = "MM/dd";
                                        break;
                                    default:
                                        strDateTimeFormat = "HH:mm";
                                        break;
                                }

                                if (_isShowHourLine)
                                {

                                    for (int i = 0; i < iDataLength; i++)
                                    {
                                        dtCurrent = _lstIndicator.Count == 0
                                                        ?   DateTime.MinValue
                                                        :   _dsDataSource.GetData(_lstIndicator[0].BaseStudy) == null
                                                            ?   DateTime.MinValue
                                                            :   _dsDataSource.GetData(_lstIndicator[0].BaseStudy).DateTime(i);

                                        if (_isShowHourLine & (dtCurrent.Minute == 0))
                                            g.DrawLine(penHour,
                                                       new Point(XInterval * (iDataLength - i - 1), TopPad),
                                                       new Point(XInterval * (iDataLength - i - 1), TopPad + iHeight));
                                    }
                                }

                                foreach (ConstantLine customLine in _lstCustomLine)
                                {
                                    g.DrawLine(new Pen(new SolidBrush(customLine.Color)),
                                               new Point(LeftPad, ValueToPixel(0, customLine.Value)[1]),
                                               new Point(LeftPad + DrawWidth, ValueToPixel(0, customLine.Value)[1]));
                                }

                                if (ShowXAxis == false)
                                    return;

                                sDateSize = _lstIndicator.Count == 0 
                                                ? new SizeF(10, 10)
                                                : _dsDataSource.GetData(_lstIndicator[0].BaseStudy) == null
                                                    ? new SizeF(10, 10)
                                                    : g.MeasureString(_dsDataSource.GetData(_lstIndicator[0].BaseStudy).DateTime().ToString(strDateTimeFormat), Font);

                                iXSkipCount = (int)Math.Ceiling(sDateSize.Width / XInterval);
                                dCount = DrawWidth / (XInterval * iXSkipCount);
                

                                for (int i = 0; (i < dCount) && (i * iXSkipCount < iDataLength); i++)
                                {
                                    dtCurrent = _lstIndicator.Count == 0 
                                                    ? DateTime.Now
                                                    : _dsDataSource.GetData(_lstIndicator[0].BaseStudy) == null
                                                        ? DateTime.Now
                                                        : _dsDataSource.GetData(_lstIndicator[0].BaseStudy).DateTime(iDataLength - i * iXSkipCount - 1);
                                    g.DrawLine(pen,
                                               new Point(iXSkipCount * i * XInterval, iHeight),
                                               new Point(iXSkipCount * i * XInterval, iHeight + 5));
                    
                                    if(dtCurrent == DateTime.MinValue)
                                        continue;
                                    strDrawString = dtCurrent.ToString(strDateTimeFormat);
                                    g.DrawString(strDrawString, Font, new SolidBrush(AxisLineColor),
                                                 new Point(iXSkipCount * i * XInterval, iHeight + 5));
                                }
                */
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }
        }

        public new void PaintChart()
        {
            try
            {
/*
                if ((DateTime.Now.Ticks - _lLastUpdateTicks) / 100000 < UpdateFreq)
                    return;
*/

                CalculateAxisRange();

/*
                for (int i = 0; i < _dMax.Length; i++)
                {
                    _dMax[i] = -double.MaxValue;
                    _dMin[i] = double.MaxValue;
                }

                foreach (IIndicator indicator in _lstIndicator)
                {
                    indicator.StartIndex = StartIndex;
                    indicator.EndIndex = EndIndex;
                    if (indicator.XAxis == ChartConstants.X)
                    {
                        XMax = Math.Max(XMax, indicator.XMax);
                        XMin = Math.Min(XMin, indicator.XMin);
                    }

                    if (indicator.YAxis == ChartConstants.Y)
                    {
                        YMax = Math.Max(YMax, indicator.YMax);
                        YMin = Math.Min(YMin, indicator.YMin);
                    }

                    if (indicator.XAxis == ChartConstants.X2)
                    {
                        X2Max = Math.Max(X2Max, indicator.XMax);
                        X2Min = Math.Min(X2Min, indicator.XMin);
                    }

                    if (indicator.YAxis == ChartConstants.Y2)
                    {
                        Y2Max = Math.Max(Y2Max, indicator.YMax);
                        Y2Min = Math.Min(Y2Min, indicator.YMin);
                    }
                }

                for (int i = 0; i < _dMax.Length; i++)
                {
                    switch (i)
                    {
                        case ChartConstants.X:
                        case ChartConstants.X2:
                            dEdge = (_dMax[i] - _dMin[i]) * _dXEdgeRatio / 2.0;
                            break;

                        case ChartConstants.Y:
                        case ChartConstants.Y2:
                            dEdge = (_dMax[i] - _dMin[i]) * _dYEdgeRatio / 2.0;
                            break;
                    }
                    _dMin[i] -= dEdge;
                    _dMax[i] += dEdge;
                }

//                X2Min = Math.Min(0, X2Min);
*/
                CalculateOrigin();
                Graphics g;
                Graphics eg = CreateGraphics();

                if (Visible == false)
                    return;

                //Bitmap bitmap = new Bitmap(DrawWidth, DrawHeight);
                Bitmap bitmap = new Bitmap(Width, Height);
                g = Graphics.FromImage(bitmap);
                //                g.Transform = CreateTransform(ChartConstants.X, ChartConstants.Y);

                DrawChartArea(g);

                foreach (IIndicator indicator in GetIndicators())
                {
                    indicator.Calculate();
                    indicator.Draw(g);
                }
               
                //eg.DrawImage(bitmap, (int)_fXOrigin, 0);
                eg.DrawImage(bitmap, 0, 0);
                eg.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }
            finally
            {
                _lLastUpdateTicks = DateTime.Now.Ticks;
            }
        }

    }
}
